package a20;

import org.springframework.beans.factory.support.DefaultSingletonBeanRegistry;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBean;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.util.Arrays;

@ComponentScan  //默认扫描所在包下
@Configuration
//springboot项目会自动读，我们这里手动通过注解读取
@PropertySource("classpath:application.properties")
//配置文件里的配置很多情况下是成组存在的，比如都是spring.mvc开头的，比如以server.开头的。因此这些属性其实可以封装成对象，下面的WebMvcProperties与ServerProperties就是例子
@EnableConfigurationProperties({WebMvcProperties.class, ServerProperties.class})
public class WebConfig {

    //内嵌Tomcat工厂
    @Bean
    TomcatServletWebServerFactory factory(){
        return new TomcatServletWebServerFactory();
    }


    @Bean
    DispatcherServlet dispatcherServlet() {
        return new DispatcherServlet();
    }

    // 注册DispatcherServlet
    @Bean
    DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet, WebMvcProperties webMvcProperties){
        DispatcherServletRegistrationBean registrationBean = new DispatcherServletRegistrationBean(dispatcherServlet, "/");
        //DispatcherServlet的初始化默认情况下在第一次http访问时初始化，通过设置load-on-startup属性，可以再web容器启动时就初始化
        registrationBean.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
        return registrationBean;
    }

    /**
     * DispatcherServlet在初始化的过程中，如果没有在容器中找到HandlerMapping，就会选用默认的。通过查看OnRefresh里的initHandlerMappings里可以看
     * 到，默认的就是DispatcherServlet.properties文件里面配置的。这里面就包含了RequestMappingHandlerMapping。但通过这种默认的初始化的方式，
     * RequestMappingHandlerMapping不会放到容器当中，我们后面想从容器中取出来调用其方法测试是办不到的。所以这里我们手动注入到容器中。
     */
    @Bean
    RequestMappingHandlerMapping handlerMapping() {
        return new RequestMappingHandlerMapping();
    }

    /**
     * 与上同理，将HandlerAdapter注入容器，覆盖默认的HandlerAdapter
     */
    @Bean
    MyRequestMappingHandlerAdapter handlerAdapter() {

        MyRequestMappingHandlerAdapter adapter = new MyRequestMappingHandlerAdapter();
        //参数解析器
        TokenArgumentResolver resolver = new TokenArgumentResolver();
        adapter.setCustomArgumentResolvers(Arrays.asList(resolver));

        //设置返回值解析器
        YmlReturnValueHandler handler = new YmlReturnValueHandler();
        adapter.setCustomReturnValueHandlers(Arrays.asList(handler));
        return adapter;
    }

}
